import json
import random
import copy
import time

import src.global_config as gl
import src.util as util
from database.dbop import Database
import database.sql as SQL
import chess
from src.chess_util import Chess
from src.mcts import Mcts


class Tal:
    def __init__(self):
        self.db_config = gl.get_value('db_config')
        self.tal_chess = Chess()
        path = util.get_config_by_key(self.db_config, 'db_path')

        e4 = util.get_config_by_key(self.db_config, 'e4')
        d4 = util.get_config_by_key(self.db_config, 'd4')
        other = util.get_config_by_key(self.db_config, 'other')
        e4_path = path + '/' + e4
        d4_path = path + '/' + d4
        other_path = path + '/' + other
        self.e4_db_handler = Database(e4_path)
        self.d4_db_handler = Database(d4_path)
        self.other_db_handler = Database(other_path)

    # 解析传来的数据
    def parse_operator(self, data) -> dict:
        data = json.loads(data)
        print("data->", data)
        operator = data['operator']
        msg = data['data']
        if operator == 'save_fen':
            # 保存棋谱
            return self.save_fen(msg)

        elif operator == 'get_fen_name':
            return self.get_fen_name(msg)
        elif operator == 'analyze':
            return self.analyze(msg)

    def save_fen(self, data: dict) -> dict:
        name = data['name']
        nameEn = data['nameEn']
        fen = data['fen']
        fen_drop = self.tal_chess.drop_last_fen(fen)
        step = data['step']
        first = data['first']
        sql = SQL.insert_data.format(name, nameEn, fen_drop, step, 0, util.getCurrentTimeStr())
        check_sql = SQL.check_data.format(fen_drop, step)
        print("保存棋谱的SQL为", sql)
        if first == 'e4':
            res = self.e4_db_handler.select(check_sql)
            if len(res) != 0:
                print("开局已经存在 取消入库")
                return {
                    'code': 1,
                    'message': '这个开局已经存在'
                }
            self.e4_db_handler.insert(sql)
        elif first == 'd4':
            res = self.d4_db_handler.select(check_sql)
            if len(res) != 0:
                print("开局已经存在 取消入库")
                return {
                    'code': 1,
                    'message': '这个开局已经存在'
                }
            self.d4_db_handler.insert(sql)
        else:
            res = self.other_db_handler.select(check_sql)
            if len(res) != 0:
                print("开局已经存在 取消入库")
                return {
                    'code': 1,
                    'message': '这个开局已经存在'
                }
            self.other_db_handler.insert(sql)
        return {
            'code': 0,
            'message': '保存棋谱成功'
        }

    # 获取这个局面的局面名称
    def get_fen_name(self, data):
        fen = data['fen']
        fen_drop = self.tal_chess.drop_last_fen(fen)
        first = data['first']
        step = data['step']
        sql = SQL.get_fen_name.format(fen_drop, step)
        print("查询开局名称的sql为", sql)
        if first == 'e4':
            res = self.e4_db_handler.select(sql)
        elif first == 'd4':
            res = self.d4_db_handler.select(sql)
        elif first == '':
            e4 = self.e4_db_handler.select(sql)
            d4 = self.d4_db_handler.select(sql)
            other = self.other_db_handler.select(sql)
            res = []
            res.extend(e4)
            res.extend(d4)
            res.extend(other)
        else:
            res = self.other_db_handler.select(sql)
        if len(res) == 0:
            return {
                'code': 0,
                'message': '获取对局名称成功',
                'data': {
                    'name': '未知对局',
                    'name_en': 'unknown',
                }
            }
        else:
            return {
                'code': 0,
                'message': '获取对局名称成功',
                'data': {
                    'name': res[0]['name'],
                    'name_en': res[0]['name_en'],
                }
            }

    # 获取开局库棋步
    def get_database_step(self, fen: str) -> list:
        drop_fen = self.tal_chess.drop_last_fen(fen)
        sql = SQL.select_open_step.format(drop_fen)
        e4 = self.e4_db_handler.select(sql)
        d4 = self.d4_db_handler.select(sql)
        other = self.other_db_handler.select(sql)
        res = []
        res.extend(e4)
        res.extend(d4)
        res.extend(other)
        return res

    # 分析模块
    def analyze(self, data):
        fen = data['fen']
        open_step = self.get_database_step(fen)
        print('获取的开局库数据为', open_step)

        board = chess.Board(fen)
        if len(open_step) > 0:
            return self.database_analyze(open_step, board)
        else:
            return self.mcts_analyze(fen)


    def mcts_analyze(self, fen: str) -> dict:
        start = time.time()
        mcts = Mcts()
        step, parsed_fen = mcts.mct_search_analyze(fen)
        parsed_board = chess.Board(parsed_fen)
        internal = self.tal_chess.parse_internal_board_info(parsed_board, parsed_fen)
        value = self.tal_chess.do_evaluate(parsed_board, internal)
        san = chess.Board(fen).san(step)
        print("san->", san)
        end = time.time()
        print("耗时->", end - start, 's')
        return {
            'code': 0,
            'data': {
                'fen': parsed_fen,
                'step': san,
                # 必须转成str 因为原来的类型是chess.Move，json没法解析
                'uci': str(step),
                'score': value,
            },
            'message': "分析成功"
        }

    # 数据库进行的分析 走开局库
    def database_analyze(self, open_step: list, board):
        rand_open = random.sample(open_step, 1)
        rand_step = [rand_open[0]['step']]
        uci = rand_step[0]
        san = uci
        board.push_san(uci)
        # after_parsed_board: list = self.tal_chess.parse_board(copy.deepcopy(board))
        internal_info = self.tal_chess.parse_internal_board_info(board, board.fen())
        score = self.tal_chess.do_evaluate(board, internal_info)

        result_fen = board.fen()
        print("分析结果为-> fen->{},step->{},uci->{},score={}".format(result_fen, san, str(uci), score))

        return {
            'code': 0,
            'data': {
                'fen': result_fen,
                'step': san,
                # 必须转成str 因为原来的类型是chess.Move，json没法解析
                'uci': str(uci),
                'score': score,
            },
            'message': "分析成功"
        }

    # Tal进行的分析
    def tal_analyze(self, fen: str, root_board: chess.Board) -> dict:
        legal_list = list(root_board.legal_moves)
        score_list = []
        pre_check = self.tal_chess.check_board_status(root_board)
        if pre_check['end'] is True:
            return {
                'code': 1,
                'message': pre_check['result'],
            }

        for i in range(len(legal_list)):
            board = chess.Board.copy(root_board)
            move = legal_list[i]

            # 先转换 如果先下棋再转换会报错非法棋步
            step = board.san(move)

            # 先放进去 然后计算估值
            board.push(move)
            internal_info = self.tal_chess.parse_internal_board_info(board, board.fen())
            score = self.tal_chess.do_evaluate(board, internal_info)
            score_list.append({
                'score': score,
                'fen': board.fen(),
                'step': step,
                'uci': move,
            })
        score_list = sorted(score_list, reverse=True, key=lambda e: e.__getitem__('score'))
        print("score_list->", score_list)
        color = self.tal_chess.get_current_color_by_fen(fen)
        print('目前的颜色为 ', color)
        # 白棋拿最高的 黑棋拿最低的
        if color is True:
            # 白棋
            res = score_list[0]
        else:
            res = util.get_list_last_item(score_list)
        return {
            'code': 0,
            'data': {
                'fen': res['fen'],
                'step': res['step'],
                # 必须转成str 因为原来的类型是chess.Move，json没法解析
                'uci': str(res['uci']),
                'score': res['score'],
            },
            'message': "分析成功"
        }
